package com.adun;

import com.adun.functioninterface.GreetingService;
import org.junit.Test;

import javax.annotation.Resource;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

/**
 * @author adun
 * <p>
 * 方法引用
 * 方法引用的语法格式：
 * （1）实例对象名::实例方法
 * （2）类名::静态方法
 * （3）类名::实例方法
 * 说明：
 * ::称为方法引用操作符（两个:中间不能有空格，而且必须英文状态下半角输入）
 * Lambda表达式的形参列表，全部在Lambda体中使用上了，要么是作为调用方法的对象，要么是作为方法的实参。
 * 在整个Lambda体中没有额外的数据。
 * <p>
 * 构造器引用
 * （1）当Lambda表达式是创建一个对象，并且满足Lambda表达式形参，正好是给创建这个对象的构造器的实参列表。
 * （2） 当Lambda表达式是创建一个数组对象，并且满足Lambda表达式形参，正好是给创建这个数组对象的长度
 * 构造器引用的语法格式：
 * • 类名::new
 * • 数组类型名::new
 */
public class LambdaTest {


    /**
     * 方法引用
     */
    @Test
    public void testLambdaFirst() {
        //初始版本
        Runnable helloLambda = new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello Lambda");
            }
        };
        Thread thread = new Thread(helloLambda);
        thread.start();

        //使用Lambda风格
        Runnable a1 = () -> System.out.println("Hello");
        Thread thread1 = new Thread(a1);
        thread1.start();

        //（1）实例对象名::实例方法
        //不能简化方法引用，因为"hello lambda"这个无法省略
        Runnable a = System.out::println;//打印空行
        Thread thread2 = new Thread(a);
        thread2.start();

    }

    /**
     * 构造器引用
     */

    @Test
    public void testLambdaSecond() {
        //测试自定义函数式接口
        GreetingService greetingService = message -> System.out.println("哈哈"+message);
        greetingService.sayMessage("嘿嘿");
        greetingService.sayMessage(0);


        //测试供给型函数式借口
        Supplier<Integer> s= new Supplier<Integer>() {
            @Override
            public Integer get() {
                return 8;
            }
        };
        System.out.println(s.get());

        Supplier<Integer> x=()->new Integer(1);
        System.out.println(x.get());


        //测试功能型函数式借口
        Function<Integer, Integer> integerIntegerFunction = Integer::new;
        System.out.println(integerIntegerFunction.apply(2));


        Function<Integer,Integer> f=Integer::new;
        System.out.println(f.apply(9));

        Predicate predicate = new Predicate() {
            @Override
            public boolean test(Object o) {
                return (Integer) o == 9;
            }
        };
        System.out.println(predicate.test(9));


    }

    //这个方法是模仿HashMap中，把你指定的数组的长度纠正为2的n次方的代码
    //createArray()的作用是，创建一个长度为2的n次方的数组
    public <R> R[] createArray(Function<Integer, R[]> fun, int length) {
        int n = length - 1;
			n |= n >>> 1;
			n |= n >>> 2;
			n |= n >>> 4;
			n |= n >>> 8;
			n |= n >>> 16;
			length = n < 0 ? 1 : n + 1;
        return fun.apply(length);
    }
    @Test
    public void test6() {
        /*
         * Function是一个函数式接口，可以用Lambda表达式赋值
         * Function<T,R>的抽象方法   R apply(T t)
         *
         * createArray这个方法中用的是Function<Integer,R[]> fun。说明T类型已经指定为Integer
         * 说明
         */
        //      Function<Integer,String[]> f = (Integer len) -> new String[len];

        //因为Lambda体是在创建一个数组对象完成的，而且Lambda表达式的形参正好是创建数组用的长度
        //通过构造器引用省略
        Function<Integer, String[]> f = String[]::new;//数组类型名::new
        String[] array = createArray(f, 10);

        System.out.println(array.length);//16
    }

    @Test
    public void test5() {
        //      Supplier<String> s = () -> new String();//通过供给型接口，提供一个空字符串对象

        //构造器引用
        //类名::new
        Supplier<String> s = String::new;//通过供给型接口，提供一个空字符串对象
        System.out.println(s);

    }


}
